package version

import (
	"strconv"
	"strings"
	"sync"
	"encoding/json"
	"io/ioutil"
	"fmt"
	"os"
)

// 版本控制类
// 设计版本号为四位整型，前两位用于大版本号，不同版本不能互通游戏，后两们用于小版本号，一般不同小版本号能互通游戏
type VersionControl struct {
	CurVersion		int		// 当前版本
	LowVersion		int		// 当前支持的最低版本
	Url 			string 	// 版本更新下载地址

	// 平台对应版本信息
	CurVersions		map[string]int		// 当前版本
	LowVersions		map[string]int		// 当前支持的最低版本
	Urls 			map[string]string 	// 版本更新下载地址
	Reviews			map[string]int 		// 用于提审的版本号

	filename		string

	mu				sync.Mutex
}

const (
	VER_SUCCESS	= 0		// 版本正确
	VER_WRONG	= 1		// 版本错误
	VER_LOW		= 2		// 版本太低，需要强更
	VER_UPDATE	= 3		// 有可更新版本
	VER_DEV		= 4		// 开发版本
	VER_REVIEW	= 5		// 提审
)

var vercontrol = VersionControl{CurVersions: make(map[string]int), LowVersions: make(map[string]int), Urls: make(map[string]string), Reviews: make(map[string]int)}

// 重启服务器后的初始化版本信息
func InitVersion(filename string) {
	vercontrol.filename = filename

	data, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Println("不存在版本信息文件", err)
		return
	}
	err = json.Unmarshal([]byte(data), &vercontrol)
	if err != nil {
		fmt.Println("解析版本信息文件内容失败", err)
	}
}

// 获取所有版本的平台信息
func GetVersionPlatforms() []string {
	ret := make([]string, 0, len(vercontrol.CurVersions))
	for k, _ := range vercontrol.CurVersions {
		ret = append(ret, k)
	}
	return ret
}

// 检查版本，返回版本对比整形常量
func CheckVersion(versionStr string, platform string) int {
	cur := GetCurPlatformVersion(platform)
	if cur == 0 {
		return VER_SUCCESS	// 没有设置版本号
	}
	low := GetLowPlatformVersion(platform)

	version, err := strconv.Atoi(strings.Replace(versionStr, ".", "", -1))
	if err != nil {
		return VER_WRONG
	}

	if version < low {
		return VER_LOW
	} else if version < cur {
		return VER_UPDATE
	}

	if IsReviewPlatform(version, platform) {
		return VER_REVIEW
	}

	return VER_SUCCESS
}

func SetCurVersion(ver int) {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	vercontrol.CurVersion = ver
	if vercontrol.LowVersion / 100 != vercontrol.CurVersion / 100 || vercontrol.LowVersion > vercontrol.CurVersion {
		vercontrol.LowVersion = vercontrol.CurVersion
	}
}

func SetCurPlatformVersion(ver int, platform string) {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	vercontrol.CurVersions[platform] = ver
	if v, ok := vercontrol.LowVersions[platform]; ok {
		if v / 100 != ver / 100 || v > ver {
			vercontrol.LowVersions[platform] = ver
		}
	} else {
		vercontrol.LowVersions[platform] = ver
	}
}

func SetCurVersionByStr(ver string) {
	version, err := strconv.Atoi(strings.Replace(ver, ".", "", -1))
	if err == nil {
		SetCurVersion(version)
	}
}

func SetCurPlatformVersionByStr(ver string, platform string) {
	version, err := strconv.Atoi(strings.Replace(ver, ".", "", -1))
	if err == nil {
		SetCurPlatformVersion(version, platform)
	}
}

func GetCurVersion() int {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	return vercontrol.CurVersion
}

func GetCurPlatformVersion(platform string) int {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	if v, ok := vercontrol.CurVersions[platform]; ok {
		return v
	}

	return vercontrol.CurVersion
}

func SetLowVersion(ver int) {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	vercontrol.LowVersion = ver
	if vercontrol.LowVersion / 100 != vercontrol.CurVersion / 100 || vercontrol.LowVersion > vercontrol.CurVersion {
		vercontrol.LowVersion = vercontrol.CurVersion
	}
}

func SetLowPlatformVersion(ver int, platform string) {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	vercontrol.LowVersions[platform] = ver
	if v, ok := vercontrol.CurVersions[platform]; ok {
		if ver / 100 != v / 100 || ver > v {
			vercontrol.LowVersions[platform] = v
		}
	} else {
		vercontrol.LowVersions[platform] = 0
	}
}

func GetLowVersion() int {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()
	
	return vercontrol.LowVersion
}

func GetLowPlatformVersion(platform string) int {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	if v, ok := vercontrol.LowVersions[platform]; ok {
		return v
	}

	return vercontrol.LowVersion
}

func SetVersionUrl(url string) {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	vercontrol.Url = url
}

func GetVersionUrl() string {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	return vercontrol.Url
}

func SetVersionPlatformUrl(url string, platform string) {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	vercontrol.Urls[platform] = url
}

func GetVersionPlatformUrl(platform string) string {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	if url, ok := vercontrol.Urls[platform]; ok {
		return url
	}
	return vercontrol.Url
}

func SetReviewPlatform(ver int, platform string) {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	vercontrol.Reviews[platform] = ver
}

func GetReviewPlatform(platform string) int {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	if v, ok := vercontrol.Reviews[platform]; ok {
		return v
	}

	return 0
}

func IsReviewPlatform(ver int, platform string) bool {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	if v, ok := vercontrol.Reviews[platform]; ok {
		return v == ver
	}

	return false
}

func SetVersion(cur int, low int) {
	vercontrol.mu.Lock()
	defer vercontrol.mu.Unlock()

	vercontrol.CurVersion = cur
	vercontrol.LowVersion = low
}

func SaveVersion() {
	fp, err := os.Create(vercontrol.filename)
	if err != nil {
		fmt.Println("创建版本信息文件失败", err)
		return
	}
	defer fp.Close()

	buf, err := json.Marshal(vercontrol)
	if err != nil {
		fmt.Println("转换版本信息到文本失败", err)
		return
	}
	_, err = fp.Write(buf)
	if err != nil {
		fmt.Println("保存版本信息到文件失败", err)
	}
}
